fix(sqlite): read generated columns with pragma_table_xinfo (weasel#426) - #433
Merged
Merged
Conversation
pragma_table_info omits generated columns entirely, so a Table declaring
one was read back without it. The delta reported the column missing on
every run, emitted ALTER TABLE ADD COLUMN, and the second migration
failed with "duplicate column name" -- such a table never converged.
Both introspection sites now query pragma_table_xinfo, whose first six
columns are table_info's in the same order, so the positional reader is
unchanged. The columns are listed explicitly rather than SELECT *, and
hidden = 1 rows are filtered out so the switch does not also start
reporting a virtual table's hidden columns as real ones.
Reading generated columns properly has two consequences for migration:
- Table recreation copied every column present on both sides, which now
includes generated columns, and SQLite refuses writes to those. They
are left out of the INSERT ... SELECT; the value re-derives from the
base columns that are copied.
- A newly declared STORED generated column cannot be introduced with
ALTER TABLE ADD COLUMN ("cannot add a STORED column"), so it forces a
recreation. VIRTUAL still takes the incremental path.
The generation expression is still not round-tripped, so a *changed*
expression is not detected -- TableColumn.Equals compares name and type
only, for every column. Documented rather than fixed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #426.
pragma_table_infoomits generated columns entirely, so aTabledeclaring one was read back without it: the delta reported the column missing on every run, emittedALTER TABLE ... ADD COLUMN, and the second migration failed withduplicate column name. Such a table never converged.The read
Both introspection sites (
ConfigureQueryCommandandFetchExistingAsync) now share one query againstpragma_table_xinfo. Its first six columns aretable_info's in the same order, so the positional reader inreadColumnsAsyncis untouched.Two deliberate details beyond the issue's sketch:
SELECT *, since the reader is positional.hidden <> 1filters out a virtual table's hidden columns, whichtable_xinforeports andtable_infonever did — for an fts5 table that is the table-name column andrank. Verified:table_xinfo('search')onfts5(title, body)returnstitle, body, search(hidden=1), rank(hidden=1).Two consequences for migration
Reading generated columns properly exposes two paths that were only accidentally safe while those columns were invisible:
INSERT ... SELECTwould fail. They are excluded; the value re-derives from the base columns that do get copied.ALTER TABLE ADD COLUMN— SQLite answerscannot add a STORED column— so it now forces a recreation. VIRTUAL still takes the incremental path.Not in scope
The generation expression is still not round-tripped, so a changed expression is not detected.
TableColumn.Equalscompares name and raw type for every column, not just generated ones, so making expressions authoritative here would be a lopsided change. Documented indocs/sqlite/tables.mdinstead.Separately, and pre-existing: Weasel.Sqlite cannot introspect a virtual table at all — fts5 columns report an empty type, which
TableColumn's constructor rejects. Unchanged by this PR, and noted in the test that covers thehiddenfilter.Tests
8 new tests in
GeneratedColumnDeltaTests, 6 of which fail onmasterfor the reasons above. Full SQLite suite: 401 passing.🤖 Generated with Claude Code